﻿namespace instamuz.Application.Controllers
{
    using System.Web.Mvc;
    using Criterias;
    using Criterias.Account;
    using Domain.Entities;
    using IndyCode.Infrastructure.Domain;
    using Services;

    public class AccountController : Controller
    {
        private readonly IUnitOfWorkFactory _unitOfWorkFactory;
        private readonly IQueryBuilder _queryBuilder;
        private readonly IAuthenticationService _authenticationService;
        private readonly IContextAccountProvider _contextAccountProvider;

        public AccountController(IUnitOfWorkFactory unitOfWorkFactory, IQueryBuilder queryBuilder,
                                 IAuthenticationService authenticationService,
                                 IContextAccountProvider contextAccountProvider)
        {
            _unitOfWorkFactory = unitOfWorkFactory;
            _queryBuilder = queryBuilder;
            _authenticationService = authenticationService;
            _contextAccountProvider = contextAccountProvider;
        }

        [HttpPost]
        public JsonResult Register(string email, string login, string password)
        {
            using (var unitOfWork = _unitOfWorkFactory.Create())
            {
                var existing = _queryBuilder
                    .For<Account>()
                    .With(new FindAccountByLoginCriteria(login));

                if (existing != null)
                    return CreateJsonResult(false, "Пользователь с таким псевдонимом уже зарегистрирован у нас");

                existing = _queryBuilder
                    .For<Account>()
                    .With(new FindAccountByEmailCriteria(email));

                if (existing != null)
                    return CreateJsonResult(false, "Пользователь с таким электронным адресом уже зарегистрирован у нас");

                var account = new Account(email, login);
                account.SetPassword(password);

                unitOfWork.Save(account);
                unitOfWork.Commit();

                _authenticationService.SignIn(account, true);

                return CreateJsonResult(true, "Поздравляем! ;)");
            }
        }

        [HttpPost]
        public JsonResult Login(string login, string password)
        {
            using (_unitOfWorkFactory.Create())
            {
                var account = _queryBuilder
                    .For<Account>()
                    .With(new FindAccountByLoginCriteria(login));

                if (account == null)
                    return CreateJsonResult(false, "Пользователь с таким псевдонимом не зарегистрирован у нас");

                if (account.Password.Check(password) == false)
                    return CreateJsonResult(false, "Введен неправильный пароль");

                _authenticationService.SignIn(account, true);
            }

            return CreateJsonResult(true, null, "/");
        }

        public ActionResult LogoutItem()
        {
            using (_unitOfWorkFactory.Create())
            {
                return PartialView("Logout", _contextAccountProvider.GetContextAccount() != null);
            }
        }

        public ActionResult Logout()
        {
            _authenticationService.SignOut();
            return RedirectToAction("index", "index");
        }

        public ActionResult Follow(int id)
        {
            using (var unitOfWork = _unitOfWorkFactory.Create())
            {
                var account = _queryBuilder
                    .For<Account>()
                    .With(new FindByIdCriteria(id));

                if (account == null)
                    return CreateJsonResult(false, "internal fail");

                var contextAccount = _contextAccountProvider.GetContextAccount();

                contextAccount.Follow(account);
                unitOfWork.Commit();

                return CreateJsonResult(true, "OK");
            }
        }

        public ActionResult Post(string description)
        {
            using (var unitOfWork = _unitOfWorkFactory.Create())
            {
                var account = _contextAccountProvider.GetContextAccount();

                account.Post(new Post(description));

                unitOfWork.Commit();

                return CreateJsonResult(true, "OK");
            }
        }

        private JsonResult CreateJsonResult(bool success, string message, string returnUrl = null)
        {
            return new JsonResult
                       {
                           Data = new
                                      {
                                          success,
                                          message,
                                          returnUrl
                                      }
                       };
        }
    }
}